package rpc.service;

import com.alibaba.fastjson.JSON;
import lombok.SneakyThrows;
import lombok.extern.java.Log;
import rpc.common.NodeInformation;
import rpc.common.RpcConfig;
import rpc.common.TaskRpc;
import rpc.units.SocketUnits;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;

@Log
public class Service {

    /**
     * 问: 是否复用第一个请求过去的socket;
     * 答: 只有serverSocket才可以高并发,所以并不可以;
     */
    private ExecutorService threadPool = Executors.newFixedThreadPool(5);
    private IUserService userService=new UserServiceImpl();

    /**
     * 服务端不仅要 接收 还需要发送
     */

    //前往注册中心进行注册
    @SneakyThrows
    private void registerServer(){

        Socket socket=new Socket();
        SocketAddress socketAddress=new InetSocketAddress(RpcConfig.CenterAddress, RpcConfig.CenterPort);

        try {
            socket.connect(socketAddress);//连接失败直接停止任务
        }catch (Exception e){
            log.log(Level.WARNING,"注册中心连接失败");
            System.exit(0);
            return;
        }

        NodeInformation nodeInformation=new NodeInformation("userService",RpcConfig.UserServiceAddress,RpcConfig.UserServicePort,1);
        //发送自己的节点信息
        SocketUnits.sendMsg(socket,JSON.toJSONString(nodeInformation));
        //问: 不关闭,用于注册中心检测心跳行不行? 答:那要多开一个线程监听数据,还不如让server解决
        this.close(socket);//注册完毕就关闭
    }

    //启动服务
    @SneakyThrows
    private void initServer(){
        ServerSocket serverSocket=new ServerSocket();
        SocketAddress socketAddress=new InetSocketAddress(RpcConfig.UserServiceAddress,RpcConfig.UserServicePort);
        serverSocket.bind(socketAddress);

        while (true){

            Socket socket = serverSocket.accept();


            threadPool.execute(()->{
                try {
                    String msg = SocketUnits.receiveMsg(socket);//接收任务

                    if(msg.equals("jump")){
                        //注册中心的心跳,返回自己的节点信息
                        SocketUnits.sendMsg(socket, JSON.toJSONString(new NodeInformation("userService",RpcConfig.UserServiceAddress,RpcConfig.UserServicePort,1)));
                        return;
                    }

                    TaskRpc taskRpc = JSON.parseObject(msg, TaskRpc.class);
                    String methodName = taskRpc.getMethodName();
                    Object[] params= taskRpc.getParams();
                    Class[] paramsClass=new Class[params.length];
                    for (int i = 0; i < params.length; i++) {
                        paramsClass[i]=params[i].getClass();
                    }
                    Method method = userService.getClass().getMethod(methodName,paramsClass);
                    Object result = method.invoke(userService, params);
                    String sendMsg = JSON.toJSONString(result);
                    System.out.println("调用成功");
                    SocketUnits.sendMsg(socket,sendMsg);//发送结果
                }catch (Exception e){
                    e.printStackTrace();
                }finally {
                    //防止连接丢失 或者 客户端不主动关闭
                    try {
                        this.close(socket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });

        }
    }

    private void close(Socket socket) throws IOException {
        socket.close();
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        Service service=new Service();
        service.registerServer();
        service.initServer();
    }


}
